oo::class create Accelerator {
    method predefine {what root num} {
        set n 1
        while {$n <= $num} {
            set th [thread::create]
            lappend pool $th
            lappend threads ThreadRet$n
            thread::send -async $th [my threadHead $root]
            incr n
        }
        oo::objdefine [self] variable {*}[concat [info class variables ::[string totitle $what]] $threads ThreadPool What LockNum]
        
        my eval [subst {
            set What $what
            set ThreadPool $pool
        }]
        my eval {
            foreach c [info class instances ::CodePad] {
                if {$RenamedPadWidget == [set [info object namespace $c]::PadWidget]} { break }
            }
            # oo::objdefine $c variable [concat [info object variables $c] LockNum]
            set LockNum [info object namespace $c]::LockNum
            set $LockNum 0
        }
        
        foreach t $threads {
            trace add variable [info object namespace [self]]::$t \
              write [list [self] hilightPad]
        }
    }
    
    method lockPad {} {
        variable RenamedPadWidget
        variable LockNum
        
        $RenamedPadWidget configure -state disable
        incr $LockNum
    }
    
    method unlockPad {} {
        variable RenamedPadWidget
        variable LockNum
        
        incr $LockNum -1
        if {[set $LockNum] == 0} {
            $RenamedPadWidget configure -state normal
        }
    }
    
    method threadHead {root} {
        set ret "lappend auto_path [file join $root lib]"
        append ret {
            foreach p {TclOO style::as tooltip Thread tkdnd BWidget} {
                package require $p
            }
            wm withdraw .
            
            proc sourceDir {dir} {
                set dirs {}
                foreach f [glob -nocomplain -directory $dir *] {
                    if {[file isdirectory $f]} {
                        lappend dirs $f
                    } elseif {[file isfile $f]} {
                        uplevel #0 source $f
                    }
                }
                foreach d $dirs {
                    sourceDir $d
                }
            }
            
            proc dump {widget from to} {
                set ret {}
                set pairs {}
                foreach {type tag id} [_$widget dump -tag $from $to] {
                    if {$type == "tagon"} {
                        lappend pairs [list $tag $id]
                    } elseif {$type == "tagoff"} {
                        set h [lindex $pairs end]
                        set pairs [lreplace $pairs end end]
                        lappend ret [concat $h $id]
                    }
                }
                after idle "$::cp destroy"
                return $ret
            }
            set ::EnglishFont {Monaco 10}
            option add *Text.font $::EnglishFont
        }
        append ret "sourceDir [file join $root src]"
        
        return $ret
    }
    
    method divideContent {from to} {
        variable RenamedPadWidget
        variable ThreadPool
        
        set totalAmount [string length [$RenamedPadWidget get $from $to]]
        set n [llength $ThreadPool]
        set size [expr $totalAmount/$n]
        set i 0 ; set ret {}
        while {$i < $n-1} {
            set end [$RenamedPadWidget index $from+${size}c]
            lappend ret [list $from $end]
            set from $end
            incr i
        }
        lappend ret [list $from $to]
        
        return $ret
    }

    method hilightPlugin {from to} {
        # more than 1000 line
        if {[expr int($to)-int($from)] > 1000} {
            my hilight $from $to
        } else {
            uplevel next $from $to
        }
    }
    
    method hilight {from to} {      
        variable RenamedPadWidget
        variable Language
        variable ThreadPool
        variable What
        
        if {$from == $to} {return}

        set i 1
        foreach range [my divideContent $from $to] th $ThreadPool {
            foreach {f t} $range {}
            set body "set cp \[CodePad new .cp [string trimleft [info object class $Language] :] {$What}\]\n"
            append body [list _.cp insert 1.0 [$RenamedPadWidget get 1.0 $f]]
            append body \n
            append body [list .cp insert $f [$RenamedPadWidget get $f $t]]
            append body \n
            append body "
            after idle {set ret \[dump .cp $f $t\]}
            vwait ret
            set ret
            "
            thread::send -async $th $body [info object namespace [self]]::ThreadRet$i
            my lockPad
            incr i
        }
    }
    
    method hilightPad {v args} {
        variable RenamedPadWidget
        
        my variable {*}[info object variable [self]]
        foreach tr [set $v] {
            foreach {tag f t} $tr {
                $RenamedPadWidget tag add $tag $f $t
            }
        }
        my unlockPad
    }
}